package com.py.custom.tms.application.current;

import org.openjdk.jol.info.ClassLayout;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * 对象头布局（64位，开启指针压缩）
 *
 * 1、Mark word
 * 	a、无锁
 * 		1~25bit：25个bit位，unused；全0
 * 		26~56bit：31个bit位，存放hashCode
 * 				调用hashCode方法时候存放，否则全0
 * 		57~57bit：1bit位，unused；全0
 * 		58~61bit：4bit位，gc年龄
 * 				保存垃圾回收次数
 * 		62~62bit：1bit位，是否偏向；
 * 				基于-XX:BiasedLockingStartupDelay=0参数配置，延迟时间
 * 				没有延迟，则该bit位为1；因为没有线程id认为匿名偏向锁，当调用hashCode方法的时候，变成0
 * 				有延迟，则在延迟时间内创建的对象为0
 * 		63~64bit：2bit位，锁标记； 01
 *
 * 	b、偏向锁
 * 		1~54bit：54个bit位，存放偏向的线程ID；
 * 		55~56bit：2个bit位，存放Epoch
 * 		57~57bit：1bit位，unused；全0
 * 		58~61bit：4bit位，gc年龄
 * 				保存垃圾回收次数
 * 		62~62bit：1bit位，偏向；全1
 * 		63~64bit：2bit位，锁标记； 01 表示偏向锁
 *
 * 	c、轻量级锁
 * 		1~62bit：指向栈中锁记录的指针
 * 		63~64bit：2bit位，锁标记； 00 表示轻量级锁
 *
 * 	d、重量级锁
 * 		1~62bit：指向重量级锁的指针，Monitor
 * 		63~64bit：2bit位，锁标记； 10 表示重量级锁
 *
 * 	e、gc标记
 * 		1~62bit：空
 * 		63~64bit：2bit位，锁标记； 11 表示gc标记
 *
 * 2、klass pointer
 * 3、array length
 *
 *
 * Synchronized锁升级流程，注意：ObjectMonitor、RecordLock
 * 	1、无锁 升级为 轻量级锁
 * 		当对象头是无锁状态，且锁偏向标志是0；获取锁之后，锁升级为轻量级锁。
 * 	2、匿名偏向锁(无锁，锁偏向标志是1) 升级为 偏向锁
 * 		当对象头匿名偏向锁；获取去锁之后，锁是偏向锁，并存储获得到锁的线程ID。
 * 	3、偏向锁 升级为 轻量级锁
 * 		当线程1已经获得偏向锁，然后同步代码块执行完了；后面线程2来获取锁，这个时候升级为轻量级锁。
 * 		注意：偏向锁 批量重偏向 和 批量撤销 以class为维度。
 * 		批量重偏向：当线程1 获得 同一个class创建出来的，40个对象锁（偏向锁），然后全部执行完同步代码块。
 * 			线程2进行获取锁，前20个对象锁会升级为轻量级锁。后面的对象锁会进行重新偏向线程2。
 * 		批量撤销：当已经执行过一次批量重偏向, 但是之后又有其它线程一直使得重偏向这个线程的偏向锁撤销次数达到阈值(默认40),
 * 			那么就会将这个锁对应的类的对象(包括后续创建的)取消偏向锁的可能。直接变成轻量级别锁。
 * 	4、偏向锁 升级为 重量级别锁
 * 		当线程1已经获得偏向锁，然后同步代码块还在执行中；后面线程2来获取锁，这个时候根据cas循环次数10次，还没获取锁，阻塞。
 * 		线程1会到安全点，然后把对象头修改成重量级锁。
 * 	5、轻量级锁 升级为 重量级别锁
 * 		当线程1已经获得轻量级锁，然后同步代码块还在执行中；后面线程2来获取锁，这个时候根据cas循环次数10次，还没获取锁，阻塞。
 * 		线程1会到安全点，然后把对象头修改成重量级锁。
 */
public class SyncTest {

    public static SyncTest syncTest = new SyncTest();

    public static void main(String[] args) throws Exception {
        sync11();
        // syncP();
        //String s = ClassLayout.parseInstance(syncTest).toPrintable();
        //printObjHeader(s);
        // syncUpgrade();
        // sync();
        // syncCallHashCode();
        // callHashCodeSync();

    }

    public static void sync11() {
        System.out.println(ClassLayout.parseInstance(syncTest).toPrintable());
        new Thread(()->{
            synchronized (syncTest) {
                System.out.println("T1" + ClassLayout.parseInstance(syncTest).toPrintable());
            }
            try {
                TimeUnit.SECONDS.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();

        try {
            TimeUnit.SECONDS.sleep(2);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        new Thread(()->{
            synchronized (syncTest) {
                System.out.println("T2" +ClassLayout.parseInstance(syncTest).toPrintable());
                try {
                    TimeUnit.SECONDS.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("T2" +ClassLayout.parseInstance(syncTest).toPrintable());
            }
        }).start();

        try {
            TimeUnit.SECONDS.sleep(2);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        new Thread(()->{
            synchronized (syncTest) {
                System.out.println("T3" +ClassLayout.parseInstance(syncTest).toPrintable());
            }
        }).start();
    }

    public static void sync01_00() throws InterruptedException {
        TimeUnit.SECONDS.sleep(5);
        List<SyncTest> locks = new ArrayList<>();
        new Thread(() -> {
            for (int i = 0; i < 41; i++) {
                SyncTest lock = new SyncTest();
                synchronized (lock) {
                    // 让这40个lock对象都偏向thread1, 并且保存至locks全局列表中
                    locks.add(lock);
                }
            }
            System.out.println("已经将40个lock对象全部偏向于[" + Thread.currentThread().getName() + "], 打印一下mark word");
            System.out.println(ClassLayout.parseInstance(locks.get(0)).toPrintable());
            try {
                TimeUnit.SECONDS.sleep(15);
            } catch (InterruptedException e) {
            }
        }, "thread1").start();
        // 等待足够长的时间thread1操作执行完
        TimeUnit.SECONDS.sleep(3);
        // 创建线程依次去对这40个偏向thread1线程的对象撤销偏向, 并升级为轻量级锁, 看看能否达到预期
        new Thread(() -> {
            for (int i = 0; i < 40; i++) {
                Object lock = locks.get(i);
                synchronized (lock) {
                    if (i >= 10 && i <= 20) {
                        System.out.println("打印[" + Thread.currentThread().getName() +
                                "]再次锁定第(" + (i + 1) + ")个lock对象时的mark word\n");
                        System.out.println(ClassLayout.parseInstance(lock).toPrintable());
                    }
                }
            }
            try {
                TimeUnit.SECONDS.sleep(15);
            } catch (InterruptedException e) {
            }
        }, "thread2").start();
        TimeUnit.SECONDS.sleep(8);
        new Thread(() -> {
            for (int i = 0; i < 41; i++) {
                SyncTest lock = locks.get(i);
                synchronized (lock) {
                    if (i > 33 && i < 41) {
                        SyncTest obj = new SyncTest();
                        System.out.println("打印[" + Thread.currentThread().getName() +
                                "]第(" + (i + 1) + ")次导致偏向于[thread2]的偏向锁撤销后, 新建Object对象的mark word");
                        System.out.println(ClassLayout.parseInstance(lock).toPrintable());
                        System.out.println(ClassLayout.parseInstance(obj).toPrintable());
                    }
                }
            }
        }, "thread3").start();
    }

    public static void syncUpgrade() {
        // -XX:+PrintFlagsFinal     打印启动参数
        // -XX:BiasedLockingStartupDelay=1000     偏向延迟的时间
        Thread t1 = new Thread(() -> {
            synchronized (syncTest) {
                System.out.println(ClassLayout.parseInstance(syncTest).toPrintable());
            }
        }, "线程1");
        t1.start();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println(ClassLayout.parseInstance(syncTest).toPrintable());

        Thread t2 = new Thread(() -> {
            synchronized (syncTest) {
                System.out.println(ClassLayout.parseInstance(syncTest).toPrintable());
            }
        }, "线程2");
        t2.start();

    }

    public static void sync() {
        // 05 00 00 00
        // 00 00 00 00
        //----- 05 ---> 0000 0101
        // 01 --> 锁标记，无锁
        // 1 --> 是否偏向锁
        // 0000 --> gc年龄
        // （25bit无用）+ （31位 可以用来存储hashCode）+ （1bit 无用）
        // 40 70 06 00  ： ClassPointer 指向 Class对象的地址
        // 对齐：12 + 4 = 16
        System.out.println(ClassLayout.parseInstance(syncTest).toPrintable());

        synchronized (syncTest) {
            // 05 40 01 68
            // e4 40 01 68

            //----- 05 ---> 0000 0101
            // 01 --> 锁标记，无锁
            // 1 --> 是否偏向锁
            // 0000 --> gc年龄
            // 0 --> 不使用

            // 40  --> 01 00 0000 : 01是epoch，00 0000+ 6*8bit = 54 bit 存放线程指针
            //（00 0000）bit + 01 68 e4 40 01 68 -->

            // 40 70 06 00
            System.out.println(ClassLayout.parseInstance(syncTest).toPrintable());
            System.out.println(ClassLayout.parseInstance(syncTest).toPrintable());
        }
        // 05 40 01 68
        // e4 40 01 68
        // 40 70 06 00
        System.out.println(ClassLayout.parseInstance(syncTest).toPrintable());
    }

    public static void syncCallHashCode() {
        // 05 00 00 00
        // 00 00 00 00
        // 40 70 06 00
        // 对齐：12 + 4 = 16
        System.out.println(ClassLayout.parseInstance(syncTest).toPrintable());
        synchronized (syncTest) {
            // 05 40 01 68
            // e4 40 01 68
            // 40 70 06 00
            System.out.println(ClassLayout.parseInstance(syncTest).toPrintable());

            System.out.println("syncTest.hashCode() = " + syncTest.hashCode());

            // 02 39 91 77
            // 8f 7f 00 00
            // 40 70 06 00
            System.out.println(ClassLayout.parseInstance(syncTest).toPrintable());
        }
        // 02 39 91 77
        // 8f 7f 00 00
        // 40 70 06 00
        System.out.println(ClassLayout.parseInstance(syncTest).toPrintable());
    }

    private static void callHashCodeSync() {
        // 05 00 00 00
        // 00 00 00 00
        // 40 70 06 00
        // 对齐：12 + 4 = 16
        System.out.println(ClassLayout.parseInstance(syncTest).toPrintable());

        System.out.println("syncTest.hashCode() = " + syncTest.hashCode());

        // 01 9a a5 ea
        // 28 00 00 00
        // 40 70 06 00
        System.out.println(ClassLayout.parseInstance(syncTest).toPrintable());

        synchronized (syncTest) {
            // 18 ca 6d 0c
            // 00 70 00 00
            // 40 70 06 00
            System.out.println(ClassLayout.parseInstance(syncTest).toPrintable());
        }
        // 01 9a a5 ea
        // 28 00 00 00
        // 40 70 06 00
        System.out.println(ClassLayout.parseInstance(syncTest).toPrintable());
    }

    private static void printObjHeader(String header) {
        System.out.println(header);
        String[] s = header.split("\n");
        String markWord = s[2].split("                           ")[1].substring(0, 11)
                + " " + s[3].split("                           ")[1].substring(0, 11);
        String[] markWords = markWord.split(" ");
        // 0~7
        String s0 = hexStr2BinStr(markWords[0]);
        String s1 = hexStr2BinStr(markWords[1]);
        String s2 = hexStr2BinStr(markWords[2]);
        String s3 = hexStr2BinStr(markWords[3]);
        String s4 = hexStr2BinStr(markWords[4]);
        String s5 = hexStr2BinStr(markWords[5]);
        String s6 = hexStr2BinStr(markWords[6]);
        String s7 = hexStr2BinStr(markWords[7]);

        String lockMark = s0.substring(6, 8);
        if ("01".equals(lockMark)) {
            String biasedMark = s0.substring(5, 6);
            if ("1".equals(biasedMark)) {
                System.out.println(Thread.currentThread().getId());
                // 匿名偏向锁、偏向锁
                System.out.println("偏向锁：" + biasedMark + biasedMark);
                System.out.println("线程id：" + s7 + s6 + s5 + s4 + s3 + s2 + s1.substring(0, 6));
            } else {
                // 无锁
                System.out.println("无锁：" + biasedMark + biasedMark);
            }
        }
    }

    private static String hexStr2BinStr(String hexString) {
        Integer value = Integer.valueOf(hexString, 16);
        String result = Integer.toBinaryString(value);
        int length = result.length();
        while (length < 8) {
            result = "0" + result;
            length++;
        }
        return result;
    }
}
